home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / netprog.zip / NETPROG.TAR / tftp / fsm.c < prev    next >
C/C++ Source or Header  |  1989-12-17  |  8KB  |  278 lines

  1. /*
  2.  * Finite state machine routines.
  3.  */
  4.  
  5. #include    "defs.h"
  6. #include    <signal.h>
  7.  
  8. #include    "rtt.h"        /* for RTT timing */
  9.  
  10. #ifdef    CLIENT
  11. int    recv_ACK(), recv_DATA(), recv_RQERR();
  12. #endif
  13.  
  14. #ifdef    SERVER
  15. int    recv_RRQ(), recv_WRQ(), recv_ACK(), recv_DATA();
  16. #endif
  17.  
  18. int    fsm_error(), fsm_invalid();
  19.  
  20. /*
  21.  * Finite state machine table.
  22.  * This is just a 2-d array indexed by the last opcode sent and
  23.  * the opcode just received.  The result is the address of a
  24.  * function to call to process the received opcode.
  25.  */
  26.  
  27. int    (*fsm_ptr [ OP_MAX + 1 ] [ OP_MAX + 1 ] ) () = {
  28.  
  29. #ifdef    CLIENT
  30.     fsm_invalid,    /* [sent = 0]        [recv = 0]            */
  31.     fsm_invalid,    /* [sent = 0]        [recv = OP_RRQ]        */
  32.     fsm_invalid,    /* [sent = 0]        [recv = OP_WRQ]        */
  33.     fsm_invalid,    /* [sent = 0]        [recv = OP_DATA]        */
  34.     fsm_invalid,    /* [sent = 0]        [recv = OP_ACK]        */
  35.     fsm_invalid,    /* [sent = 0]        [recv = OP_ERROR]        */
  36.  
  37.     fsm_invalid,    /* [sent = OP_RRQ]   [recv = 0]            */
  38.     fsm_invalid,    /* [sent = OP_RRQ]   [recv = OP_RRQ]        */
  39.     fsm_invalid,    /* [sent = OP_RRQ]   [recv = OP_WRQ]        */
  40.     recv_DATA,        /* [sent = OP_RRQ]   [recv = OP_DATA]        */
  41.     fsm_invalid,    /* [sent = OP_RRQ]   [recv = OP_ACK]        */
  42.     recv_RQERR,        /* [sent = OP_RRQ]   [recv = OP_ERROR]        */
  43.  
  44.     fsm_invalid,    /* [sent = OP_WRQ]   [recv = 0]            */
  45.     fsm_invalid,    /* [sent = OP_WRQ]   [recv = OP_RRQ]        */
  46.     fsm_invalid,    /* [sent = OP_WRQ]   [recv = OP_WRQ]        */
  47.     fsm_invalid,    /* [sent = OP_WRQ]   [recv = OP_DATA]        */
  48.     recv_ACK,        /* [sent = OP_WRQ]   [recv = OP_ACK]        */
  49.     recv_RQERR,        /* [sent = OP_WRQ]   [recv = OP_ERROR]        */
  50.  
  51.     fsm_invalid,    /* [sent = OP_DATA]  [recv = 0]            */
  52.     fsm_invalid,    /* [sent = OP_DATA]  [recv = OP_RRQ]        */
  53.     fsm_invalid,    /* [sent = OP_DATA]  [recv = OP_WRQ]        */
  54.     fsm_invalid,    /* [sent = OP_DATA]  [recv = OP_DATA]        */
  55.     recv_ACK,        /* [sent = OP_DATA]  [recv = OP_ACK]        */
  56.     fsm_error,    /* [sent = OP_DATA]  [recv = OP_ERROR]        */
  57.  
  58.     fsm_invalid,    /* [sent = OP_ACK]   [recv = 0]            */
  59.     fsm_invalid,    /* [sent = OP_ACK]   [recv = OP_RRQ]        */
  60.     fsm_invalid,    /* [sent = OP_ACK]   [recv = OP_WRQ]        */
  61.     recv_DATA,        /* [sent = OP_ACK]   [recv = OP_DATA]        */
  62.     fsm_invalid,    /* [sent = OP_ACK]   [recv = OP_ACK]        */
  63.     fsm_error,    /* [sent = OP_ACK]   [recv = OP_ERROR]        */
  64.  
  65.     fsm_invalid,    /* [sent = OP_ERROR] [recv = 0]            */
  66.     fsm_invalid,    /* [sent = OP_ERROR] [recv = OP_RRQ]        */
  67.     fsm_invalid,    /* [sent = OP_ERROR] [recv = OP_WRQ]        */
  68.     fsm_invalid,    /* [sent = OP_ERROR] [recv = OP_DATA]        */
  69.     fsm_invalid,    /* [sent = OP_ERROR] [recv = OP_ACK]        */
  70.     fsm_error    /* [sent = OP_ERROR] [recv = OP_ERROR]        */
  71. #endif    /* CLIENT */
  72.  
  73. #ifdef    SERVER
  74.     fsm_invalid,    /* [sent = 0]        [recv = 0]            */
  75.     recv_RRQ,        /* [sent = 0]        [recv = OP_RRQ]        */
  76.     recv_WRQ,        /* [sent = 0]        [recv = OP_WRQ]        */
  77.     fsm_invalid,    /* [sent = 0]        [recv = OP_DATA]        */
  78.     fsm_invalid,    /* [sent = 0]        [recv = OP_ACK]        */
  79.     fsm_invalid,    /* [sent = 0]        [recv = OP_ERROR]        */
  80.  
  81.     fsm_invalid,    /* [sent = OP_RRQ]   [recv = 0]            */
  82.     fsm_invalid,    /* [sent = OP_RRQ]   [recv = OP_RRQ]        */
  83.     fsm_invalid,    /* [sent = OP_RRQ]   [recv = OP_WRQ]        */
  84.     fsm_invalid,    /* [sent = OP_RRQ]   [recv = OP_DATA]        */
  85.     fsm_invalid,    /* [sent = OP_RRQ]   [recv = OP_ACK]        */
  86.     fsm_invalid,    /* [sent = OP_RRQ]   [recv = OP_ERROR]        */
  87.  
  88.     fsm_invalid,    /* [sent = OP_WRQ]   [recv = 0]            */
  89.     fsm_invalid,    /* [sent = OP_WRQ]   [recv = OP_RRQ]        */
  90.     fsm_invalid,    /* [sent = OP_WRQ]   [recv = OP_WRQ]        */
  91.     fsm_invalid,    /* [sent = OP_WRQ]   [recv = OP_DATA]        */
  92.     fsm_invalid,    /* [sent = OP_WRQ]   [recv = OP_ACK]        */
  93.     fsm_invalid,    /* [sent = OP_WRQ]   [recv = OP_ERROR]        */
  94.  
  95.     fsm_invalid,    /* [sent = OP_DATA]  [recv = 0]            */
  96.     fsm_invalid,    /* [sent = OP_DATA]  [recv = OP_RRQ]        */
  97.     fsm_invalid,    /* [sent = OP_DATA]  [recv = OP_WRQ]        */
  98.     fsm_invalid,    /* [sent = OP_DATA]  [recv = OP_DATA]        */
  99.     recv_ACK,        /* [sent = OP_DATA]  [recv = OP_ACK]        */
  100.     fsm_error,    /* [sent = OP_DATA]  [recv = OP_ERROR]        */
  101.  
  102.     fsm_invalid,    /* [sent = OP_ACK]   [recv = 0]            */
  103.     fsm_invalid,    /* [sent = OP_ACK]   [recv = OP_RRQ]        */
  104.     fsm_invalid,    /* [sent = OP_ACK]   [recv = OP_WRQ]        */
  105.     recv_DATA,        /* [sent = OP_ACK]   [recv = OP_DATA]        */
  106.     fsm_invalid,    /* [sent = OP_ACK]   [recv = OP_ACK]        */
  107.     fsm_error,    /* [sent = OP_ACK]   [recv = OP_ERROR]        */
  108.  
  109.     fsm_invalid,    /* [sent = OP_ERROR] [recv = 0]            */
  110.     fsm_invalid,    /* [sent = OP_ERROR] [recv = OP_RRQ]        */
  111.     fsm_invalid,    /* [sent = OP_ERROR] [recv = OP_WRQ]        */
  112.     fsm_invalid,    /* [sent = OP_ERROR] [recv = OP_DATA]        */
  113.     fsm_invalid,    /* [sent = OP_ERROR] [recv = OP_ACK]        */
  114.     fsm_error    /* [sent = OP_ERROR] [recv = OP_ERROR]        */
  115. #endif    /* SERVER */
  116. };
  117.  
  118. #ifdef    DATAGRAM
  119. static struct rtt_struct   rttinfo;    /* used by the rtt_XXX() functions */
  120. static int           rttfirst = 1;
  121.  
  122. int    tout_flag;    /* set to 1 by SIGALRM handler */
  123. #endif    /* DATAGRAM */
  124.  
  125. /*
  126.  * Main loop of finite state machine.
  127.  *
  128.  * For the client, we're called after either an RRQ or a WRQ has been
  129.  * sent to the other side.
  130.  *
  131.  * For the server, we're called after either an RRQ or a WRQ has been
  132.  * received from the other side.  In this case, the argument will be a
  133.  * 0 (since nothing has been sent) but the state table above handles
  134.  * this.
  135.  */
  136.  
  137. int        /* return 0 on normal termination, -1 on timeout */
  138. fsm_loop(opcode)
  139. int    opcode;        /* for client: RRQ or WRQ */
  140.             /* for server: 0 */
  141. {
  142.     register int    nbytes;
  143.  
  144.     op_sent = opcode;
  145.  
  146. #ifdef    DATAGRAM
  147.  
  148.     if (rttfirst) {
  149.         rtt_init(&rttinfo);
  150.         rttfirst = 0;
  151.     }
  152.  
  153.     rtt_newpack(&rttinfo);        /* initialize for a new packet */
  154.  
  155.     for ( ; ; ) {
  156.         int    func_timeout();        /* our signal handler */
  157.  
  158.         signal(SIGALRM, func_timeout);
  159.         tout_flag = 0;
  160.         alarm(rtt_start(&rttinfo));    /* calc timeout & start timer */
  161.  
  162.         if ( (nbytes = net_recv(recvbuff, MAXBUFF)) < 0) {
  163.             if (tout_flag) {
  164.                 /*
  165.                  * The receive timed out.  See if we've tried
  166.                  * enough, and if so, return to caller.
  167.                  */
  168.  
  169.                 if (rtt_timeout(&rttinfo) < 0) {
  170. #ifdef    CLIENT
  171.                     printf("Transfer timed out\n");
  172. #endif
  173.                     return(-1);
  174.                 }
  175.  
  176.                 if (traceflag)
  177.                     rtt_debug(&rttinfo);
  178.             } else
  179.                 err_dump("net_recv error");
  180.  
  181.             /*
  182.              * Retransmit the last packet.
  183.              */
  184.  
  185.             net_send(sendbuff, sendlen);
  186.             continue;
  187.         }
  188.  
  189.         alarm(0);        /* stop signal timer */
  190.         tout_flag = 0;
  191.         rtt_stop(&rttinfo);    /* stop RTT timer, calc new values */
  192.  
  193.         if (traceflag)
  194.             rtt_debug(&rttinfo);
  195.  
  196. #else    /* else we have a connection-oriented protocol (makes life easier) */
  197.  
  198.     for ( ; ; ) {
  199.         if ( (nbytes = net_recv(recvbuff, MAXBUFF)) < 0)
  200.             err_dump("net_recv error");
  201.  
  202. #endif    /* DATAGRAM */
  203.  
  204.         if (nbytes < 4)
  205.             err_dump("receive length = %d bytes", nbytes);
  206.  
  207.         op_recv = ldshort(recvbuff);
  208.  
  209.         if (op_recv < OP_MIN || op_recv > OP_MAX)
  210.             err_dump("invalid opcode received: %d", op_recv);
  211.  
  212.         /*
  213.          * We call the appropriate function, passing the address
  214.          * of the receive buffer and its length.  These arguments
  215.          * ignore the received-opcode, which we've already processed.
  216.          *
  217.          * We assume the called function will send a response to the
  218.          * other side.  It is the called function's responsibility to
  219.          * set op_sent to the op-code that it sends to the other side.
  220.          */
  221.  
  222.         if ((*fsm_ptr[op_sent][op_recv])(recvbuff + 2, nbytes - 2) < 0){
  223.             /*
  224.              * When the called function returns -1, this loop
  225.              * is done.  Turn off the signal handler for
  226.              * timeouts and return to the caller.
  227.              */
  228.  
  229.             signal(SIGALRM, SIG_DFL);
  230.             return(0);
  231.         }
  232.     }
  233. }
  234.  
  235. #ifdef    DATAGRAM
  236.  
  237. /*
  238.  * Signal handler for timeouts.
  239.  * Just set the flag that is looked at above when the net_recv()
  240.  * returns an error (interrupted system call).
  241.  */
  242.  
  243. int
  244. func_timeout()
  245. {
  246.     tout_flag = 1;        /* set flag for function above */
  247. }
  248.  
  249. #endif    /* DATAGRAM */
  250.  
  251. /*
  252.  * Error packet received and we weren't expecting it.
  253.  */
  254.  
  255. /*ARGSUSED*/
  256. int
  257. fsm_error(ptr, nbytes)
  258. char    *ptr;
  259. int    nbytes;
  260. {
  261.     err_dump("error received: op_sent = %d, op_recv = %d",
  262.                     op_sent, op_recv);
  263. }
  264.  
  265. /*
  266.  * Invalid state transition.  Something is wrong.
  267.  */
  268.  
  269. /*ARGSUSED*/
  270. int
  271. fsm_invalid(ptr, nbytes)
  272. char    *ptr;
  273. int    nbytes;
  274. {
  275.     err_dump("protocol botch: op_sent = %d, op_recv = %d",
  276.                         op_sent, op_recv);
  277. }
  278.